package manager
{
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;

	/**
	 *拖拽管理类 
	 * @author 张进辉
	 * 
	 */	
	public class DragManager
	{
		public function DragManager()
		{
			throw new Error("该类为静态类，不需要实例化");
		}
		/**拖拽准备就绪*/
		private static var _isReady:Boolean = false;
		/**是否正在拖动*/
		private static var _isDraging:Boolean = false;
		/**移动时的显示对象*/
		private static var _proxyImg:Sprite;
		/**当前应用舞台*/
		private static var _stage:Stage;
		/**移动时划过的对象*/
		private static var _currentTarget:Object;
		/**启动拖拽的对象*/
		private static var _dragInitiator:Sprite;
		/**放置目标的对象*/
		private static var _dropTarget:Sprite;
		/**携带的数据*/
		private static var _dragSource:DragSource;
		/**临时显示对象的初始坐标*/
		private static var _dragX:Number = 0;
		private static var _dragY:Number = 0;
		/**经过的组件数量*/
		private static var _overPath:int;

		/**拖动时经过的组件数量，该属性为满足一些特殊需要使用*/
		public static function get overPath():int
		{
			return _overPath;
		}

		/**是否正在拖动*/
		public static function get isDraging():Boolean
		{
			return _isDraging;
		}

		/**
		 *启动拖拽,只能启动一个拖拽实例
		 * @param dragInitiator：启动拖拽的对象
		 * @param dragSource：携带的数据
		 * @param dragProxy：临时显示的图像
		 * @param offsetX：图像与启动对象的偏移x
		 * @param offsetY：图像与启动对象的偏移y
		 * 
		 */		
		public static function doDrag(dragInitiator:Sprite,dragSource:DragSource,
									  dragProxy:Sprite,event:MouseEvent,
									  offsetX:Number=0,offsetY:Number=0,
									  imgAlpha:Number=0.7):void
		{
			if(_isDraging) return;
			_isReady = true;
			
			_dragInitiator = dragInitiator;
			_dragSource = dragSource;
			_proxyImg = dragProxy;
			_proxyImg.alpha = imgAlpha;
			
			_dragX = event.stageX + offsetX - event.localX;
			_dragY = event.stageY + offsetY - event.localY;
			
			//监听舞台鼠标事件
			_stage = _dragInitiator.stage;
			_stage.addEventListener(MouseEvent.MOUSE_OUT,inititorOut);
			_stage.addEventListener(MouseEvent.MOUSE_OVER,inititorOver);
			_stage.addEventListener(MouseEvent.MOUSE_MOVE,inititorMove);
			_stage.addEventListener(MouseEvent.MOUSE_UP,inititorUp);
		}
		/**
		 *设定接收拖拽目标的对象 
		 * @param dragTarget：接收拖拽的目标
		 * 
		 */		
		public static function doAccept(dragTarget:Sprite):void
		{
			if(!_isDraging) return;
			_dropTarget = dragTarget;
		}
		/**
		 *强制停止拖拽，将摧毁所有数据 
		 * 
		 */		
		public static function doStop():void
		{
			if(!_isDraging) return;
			
			clearEvent();
			destroy();
		}
		/**
		 *显示代理图像 
		 * 
		 */		
		private static function showProxyImg():void
		{
			var nc:int = _stage.numChildren;
			_proxyImg.mouseEnabled = false;
			_proxyImg.mouseChildren = false;
			_proxyImg.x = _stage.mouseX - _proxyImg.width*0.5;
			_proxyImg.y = _stage.mouseY - _proxyImg.height*0.5;
			_stage.addChildAt(_proxyImg,nc);
		}
		/**
		 *move事件 
		 * @param event
		 * 
		 */		
		private static function inititorMove(event:MouseEvent):void
		{
			if(_isReady)
			{
				_isReady = false;
				_isDraging = true;//拖拽开始
				
				showProxyImg();//显示拖拽图像
				_dragInitiator.dispatchEvent(new//派发拖动开始事件
					DragEvent(DragEvent.DRAG_START,false,true,_dragInitiator,_dragSource));
			}
			
			_proxyImg.x = event.stageX - _proxyImg.width*0.5;
			_proxyImg.y = event.stageY - _proxyImg.height*0.5;
			
			if(event.target is Stage) return;
			if(event.target != _currentTarget)
			{
				_currentTarget = event.target;
				_currentTarget.dispatchEvent(new 
					DragEvent(DragEvent.DRAG_ENTER,false,true,_dragInitiator,_dragSource));
				_overPath ++;
			}
		}
		
		/**
		 *over事件 
		 * @param event
		 * 
		 */		
		private static function inititorOver(event:MouseEvent):void
		{
			if(event.target is Stage) return;
			
			event.target.dispatchEvent(new //派发over事件
				DragEvent(DragEvent.DRAG_OVER,false,true,_dragInitiator,_dragSource));
		}
		
		/**
		 *out事件 
		 * @param event
		 * 
		 */		
		private static function inititorOut(event:MouseEvent):void
		{
			event.target.dispatchEvent(new //派发事件
				DragEvent(DragEvent.DRAG_EXIT,false,true,_dragInitiator,_dragSource));
			
			if(_dropTarget == event.target) //离开放置目标
				_dropTarget = null;
		}
		
		/**
		 *up事件 
		 * @param event
		 * 
		 */		
		private static function inititorUp(event:MouseEvent):void
		{
			clearEvent();
			
			if(!_isDraging)//如果拖拽未启动,清理数据
			{
				clearData();
				return;
			}
			
			if(_dropTarget)//如果接收的目标存在，则直接销毁数据
			{
				_dropTarget.dispatchEvent(new 
					DragEvent(DragEvent.DRAG_DROP,false,true,_dragInitiator,_dragSource));
				destroy();
				return;
			}
			//如果接收的目标不存在，则将图像移动到拖拽启动器的位置，再销毁
			_stage.addEventListener(Event.ENTER_FRAME,tweenImg);
			_dragInitiator.dispatchEvent(new 
				DragEvent(DragEvent.DRAG_DROP,false,true,_dragInitiator,_dragSource));
		}
		/**
		 *最终销毁
		 * 
		 */		
		private static function destroy():void
		{
			if(_dropTarget)//拖拽成功完成
				_dragInitiator.dispatchEvent(new 
					DragEvent(DragEvent.DRAG_COMPLETE,false,true,_dragInitiator,_dragSource));
			
			if(_stage)
			{
				_stage.removeEventListener(Event.ENTER_FRAME,tweenImg);
				_stage.removeChild(_proxyImg);
			}
			
			clearData();
		}
		/**
		 *清理拖拽事件 
		 * 
		 */		
		private static function clearEvent():void
		{
			if(!_stage) return;
			_stage.removeEventListener(MouseEvent.MOUSE_OUT,inititorOut);
			_stage.removeEventListener(MouseEvent.MOUSE_OVER,inititorOver);
			_stage.removeEventListener(MouseEvent.MOUSE_MOVE,inititorMove);
			_stage.removeEventListener(MouseEvent.MOUSE_UP,inititorUp);
		}
		/**
		 *清理拖拽数据 
		 * 
		 */		
		private static function clearData():void
		{
			if(_dragSource)
				_dragSource.destroy();
			
			_currentTarget = null;
			_dropTarget = null;
			_dragSource = null;
			_proxyImg = null;
			_dragInitiator = null;
			_stage = null;
			_isDraging = false;
			_overPath = 0;
			_isReady = false;
		}
		/**
		 *未放置目标时将图像返回至初始位置 
		 * @param e
		 * 
		 */		
		private static function tweenImg(e:Event):void
		{
			var vx:Number = _dragX - _proxyImg.x;
			var vy:Number = _dragY - _proxyImg.y;
			var dis:Number = vx*vx+vy*vy;
			if(dis<=5)
				destroy();
			else
			{
				_proxyImg.x += vx*0.5;
				_proxyImg.y += vy*0.5;
			}
		}
	}
}